#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   CAN.py
@Time    :   2022/02/21 10:45:14
@Author  :   WangWei 
@Version :   1.0
@Contact :   wangwei@chengtech.com
@License :   (C)Copyright 2022-2025
@Desc    :   None
'''

# here put the import lib
from ctypes import *
import struct
import time

class INIT_CONFIG(Structure):
    _fields_ = [
        ('AccCode', c_uint),
        ('AccMask', c_uint),
        ('Reserved', c_uint),
        ('Filter', c_ubyte),
        ('Timing0', c_ubyte),
        ('Timing1', c_ubyte),
        ('Mode', c_ubyte),
    ]

class CAN_OBJ(Structure):
    _fields_ = [
        ('ID', c_uint),
        ('TimeStamp', c_uint),
        ('TimeFlag', c_ubyte),
        ('SendType', c_ubyte),
        ('RemoteFlag', c_ubyte),
        ('ExternFlag', c_ubyte),
        ('DataLen', c_ubyte),
        ('Data', c_ubyte * 8),
        ('Reserved', c_ubyte * 3),
    ]

class eCanVci(object):
    def __init__(self, canIdx = 0):
        self.deviceType = 4
        self.canIdx = canIdx
        self.lib = CDLL('./comm/DLL/ECanVci64.dll')
        self.rxMsg = (1000 * CAN_OBJ)()
        self.status = self.lib.OpenDevice(self.deviceType, self.canIdx, 0)

    def __del__(self):
        self.lib.CloseDevice(self.deviceType, self.canIdx)

    def init(self, speed, ch):
        init_config = INIT_CONFIG()

        init_config.AccCode = 0
        init_config.AccMask = 0xffffffff
        init_config.Filter = 0
        init_config.Mode = 0
        init_config.Timing0 = 0
        if speed == 500000:
            init_config.Timing1 = 0x1c
        else:
            init_config.Timing1 = 0x14

        ret = self.lib.InitCAN(self.deviceType, self.canIdx, ch, byref(init_config))
        if ret == 1:
            ret = self.lib.StartCAN(self.deviceType, self.canIdx, ch)

        return ret
    
    def open(self, speed1 = 500000, speed2 = 0):
        ret = self.status
        if ret == 1:
            if speed1 != 0:
                ret = self.init(speed1, 0)
            
            if speed2 != 0:
                ret = self.init(speed2, 1)

        return ret

    def clearBuffer(self, ch):
        self.lib.ClearBuffer(self.deviceType, self.canIdx, ch)

    def getReceiveNum(self, ch):
        return self.lib.GetReceiveNum(self.deviceType, self.canIdx, ch)

    def receive(self, ch, timeout=0):
        num = self.getReceiveNum(ch)
        if num <= 0:
            return None
        elif num > 1000:
            num = 1000
            
        num = self.lib.Receive(self.deviceType, self.canIdx, ch, self.rxMsg, num, timeout)
        if num > 0:
            return self.rxMsg[:num]
        else:
            return None

    def send(self, ch, id, data):
        msg = CAN_OBJ()
        msg.ID = id
        msg.DataLen = len(data)
        for i in range(len(data)):
            msg.Data[i] = data[i]

        return self.lib.Transmit(self.deviceType, self.canIdx, ch, byref(msg), 1)

    def close(self):
        return self.lib.CloseDevice(self.deviceType, self.canIdx)


#===========================================================================
# GC CAN 
#===========================================================================

# can = eCanVci()
# ret = can.open(500000, 500000)
# time.sleep(1)
# while True:
#     can.send(1,0x101,[1,2,3,4,15,16,17,18])
#     time.sleep(0.5)
#     msg = can.receive(0)
#     for m in msg:
#         print('ID {:x}'.format(m.ID))
#         print(*(m.Data))

#===========================================================================
# GC CAN FD
#===========================================================================
class INIT_CONFIG_FD(Structure):
    _fields_ = [
        ('CanReceMode',	c_ubyte),
        ('CanSendMode',	c_ubyte),		
        ('NominalBitRate',	c_uint),
        ('DataBitRate',	c_uint),
        ('FilterUsedBits', c_ubyte),	
        ('StdOrExdBits', c_ubyte),	
        ('NominalBitRateSelect', c_ubyte),
        ('DataBitRateSelect', c_ubyte),
        ('StandardORExtendedfilter1',	c_uint),
        ('StandardORExtendedfilter1Mask',	c_uint),
        ('StandardORExtendedfilter2',	c_uint),
        ('StandardORExtendedfilter2Mask',	c_uint),
        ('StandardORExtendedfilter3',	c_uint),
        ('StandardORExtendedfilter3Mask',	c_uint),
        ('StandardORExtendedfilter4',	c_uint),
        ('StandardORExtendedfilter4Mask',	c_uint),
        ('StandardORExtendedfilter5',	c_uint),
        ('StandardORExtendedfilter5Mask',	c_uint),
        ('StandardORExtendedfilter6',	c_uint),
        ('StandardORExtendedfilter6Mask',	c_uint),
        ('StandardORExtendedfilter7',	c_uint),
        ('StandardORExtendedfilter7Mask',	c_uint),
        ('StandardORExtendedfilter8',	c_uint),
        ('StandardORExtendedfilter8Mask',	c_uint),
    ]

class CAN_FD_OBJ(Structure):
    _fields_ = [
        ('CanORCanfdType', c_ubyte),
        ('DataLen', c_ubyte),
        ('Reserved', c_ubyte * 2),
        ('ID', c_uint),
        ('mday', c_ubyte),
        ('hour', c_ubyte),
        ('minute', c_ubyte),
        ('second', c_ubyte),
        ('millisecond', c_uint16),
        ('microsecond', c_uint16),
        ('Data', c_ubyte * 64),
    ]

class eCanFDVci(object):
    def __init__(self, canIdx = 0):
        self.deviceType = 6
        self.canIdx = canIdx
        self.lib = WinDLL('ECANFDVCI64.dll')
        self.CANFD_RECEFBUFFER_MAX_NUMBER = 10000
        self.rxMsg = (CAN_FD_OBJ * self.CANFD_RECEFBUFFER_MAX_NUMBER)()
        self.bitDataDict = {1000000:0, 500000:2, 250000:4}
        self.dataRateDict = {5000000:0, 4000000:1, 2000000:2, 1000000:3, 500000:5}

    def __del__(self):
        self.lib.CloseDeviceFD(self.deviceType, self.canIdx)

    def open(self, ch, speed = 1000000, dataSpeed = 5000000):
        ret = self.lib.OpenDeviceFD(self.deviceType, self.canIdx)
        if ret == 0:
            init_config = INIT_CONFIG_FD()

            init_config.NominalBitRateSelect = self.bitDataDict[speed]
            init_config.DataBitRateSelect = self.dataRateDict[dataSpeed]
            init_config.DataBitRate = 0
            init_config.CanReceMode = 3
            init_config.CanSendMode = 1

            ret = self.lib.InitCANFD(self.deviceType, self.canIdx, ch, byref(init_config))
            if ret == 0:
                ret = self.lib.StartCANFD(self.deviceType, self.canIdx, ch)

        return ret

    def receive(self, ch):
        num = c_int(0)

        self.lib.Receive_buffer_thread(self.deviceType, self.canIdx, 10)
        self.lib.ReceiveFD(self.deviceType, self.canIdx, ch, self.rxMsg, byref(num))
            
        return self.rxMsg[:num.value]

    def send(self, ch, id, data):
        msg = CAN_FD_OBJ()
        msg.ID = id
        msg.Data = data
        msg.DataLen = len(data)

        return self.lib.TransmitFD(self.deviceType, self.canIdx, ch, byref(msg), 1)

    def close(self):
        return self.lib.CloseDeviceFD(self.deviceType, self.canIdx)

# canfd = eCanFDVci()
# ret = canfd.open(0, 500000, 2000000)
# while True:
#     msg = canfd.receive(0)
#     for m in msg:
#         print('ID {:x}'.format(m.ID))

#===========================================================================
# canalyst-ii
#===========================================================================
class canalyst(object):
    def __init__(self, canIdx = 0):
        self.deviceType = 4
        self.canIdx = canIdx
        self.lib = windll.LoadLibrary('ControlCAN.dll')
        self.rxMsg = (1000 * CAN_OBJ)()
        self.status = self.lib.VCI_OpenDevice(self.deviceType, self.canIdx, 0)

    def __del__(self):
        self.lib.VCI_CloseDevice(self.deviceType, self.canIdx)

    def init(self, speed, ch):
        init_config = INIT_CONFIG()

        init_config.AccCode = 0
        init_config.AccMask = 0xffffffff
        init_config.Filter = 0
        init_config.Mode = 0
        init_config.Timing0 = 0
        if speed == 500000:
            init_config.Timing1 = 0x1c
        else:
            init_config.Timing1 = 0x14

        ret = self.lib.VCI_InitCAN(self.deviceType, self.canIdx, ch, byref(init_config))
        if ret == 1:
            ret = self.lib.VCI_StartCAN(self.deviceType, self.canIdx, ch)

        return ret
    
    def open(self, speed1 = 500000, speed2 = 0):
        ret = self.status
        if ret == 1:
            if speed1 != 0:
                ret = self.init(speed1, 0)
            
            if speed2 != 0:
                ret = self.init(speed2, 1)

        return ret

    def clearBuffer(self, ch):
        self.lib.VCI_ClearBuffer(self.deviceType, self.canIdx, ch)

    def getReceiveNum(self, ch):
        return self.lib.VCI_GetReceiveNum(self.deviceType, self.canIdx, ch)

    def receive(self, ch, timeout=0):
        num = self.getReceiveNum(ch)
        if num <= 0:
            return None
            
        num = self.lib.VCI_Receive(self.deviceType, self.canIdx, ch, self.rxMsg, num, timeout)
        if num > 0:
            return self.rxMsg[:num]
        else:
            return None

    def send(self, ch, id, data):
        msg = CAN_OBJ()
        msg.ID = id
        msg.DataLen = 8
        for i in range(8):
            msg.Data[i] = data[i]

        return self.lib.VCI_Transmit(self.deviceType, self.canIdx, ch, byref(msg), 1)

    def close(self):
        return self.lib.VCI_CloseDevice(self.deviceType, self.canIdx)